using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

// TODO: replace these with the processor input and output types.
using TInput = System.String;
using TOutput = System.String;

namespace ModelBoundingBoxProcessor
{
    [ContentProcessor(DisplayName="ModelBoundingBoxProcessor")]
    public class ModelBoundingBoxProcessor : ModelProcessor
    {
        float minX = float.MaxValue;
        float minY = float.MaxValue;
        float minZ = float.MaxValue;
        float maxX = float.MinValue;
        float maxY = float.MinValue;
        float maxZ = float.MinValue;



        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            NodeContentCollection nodeContentCollection = input.Children;

            //This is a recursive function in case the input's children have children.
            parseChildren(nodeContentCollection);

            ModelContent modelContent = base.Process(input, context);

            Vector3 min = new Vector3(minX, minY, minZ);
            Vector3 max = new Vector3(maxX, maxY, maxZ);

            modelContent.Tag = new BoundingBox(min, max);

            foreach (var mesh in modelContent.Meshes)
            {
                Vector3 meshMin = mesh.SourceMesh.Positions[0];
                Vector3 meshMax = mesh.SourceMesh.Positions[0];

                foreach (var v in mesh.SourceMesh.Positions)
                {
                    meshMin = Vector3.Min(meshMin, v);
                    meshMax = Vector3.Max(meshMax, v);
                }

                mesh.Tag = new BoundingBox(meshMin, meshMax);
            }

            return modelContent;
        }

        private void parseChildren(NodeContentCollection nodeContentCollection)
        {
            foreach (NodeContent nodeContent in nodeContentCollection)
            {
                if (nodeContent is MeshContent)
                {

                    MeshContent meshContent = (MeshContent)nodeContent;
                    foreach (Vector3 vector in meshContent.Positions)
                    {

                        if (vector.X < minX)
                            minX = vector.X;

                        if (vector.Y < minY)
                            minY = vector.Y;

                        if (vector.Z < minZ)
                            minZ = vector.Z;

                        if (vector.X > maxX)
                            maxX = vector.X;

                        if (vector.Y > maxY)
                            maxY = vector.Y;

                        if (vector.Z > maxZ)
                            maxZ = vector.Z;
                    }

                }
                else
                {
                    parseChildren(nodeContent.Children);
                }
            }
        }
    }
}